﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="TestMultiplyDenseVector.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.Tests.MatrixExtensionsTest.DoubleExtensions
{
    #region Usings

    using ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions;

    using NUnit.Framework;

    #endregion

    /// <summary>
    ///     Test suite for <see cref="MatrixExtensions.Multiply(Matrix{double},DenseVector{double},DenseVector{double})"/>.
    /// </summary>
    [TestFixture]
    [Category("ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions.MatrixExtensions")]
    public sealed class TestMultiplyDenseVector
    {
        #region Methods

        #region public

        /// <summary>
        ///     Tests the method when matrix has <see cref="CMDenseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCMDenseMatrixType()
        {
            // Arrange
            var multiplicandData = new[]
                                   {
                                       new double[] { 1, 2 },
                                       new double[] { 3, 4 },
                                       new double[] { 5, 6 }
                                   };
            var multiplicand = new CMDenseMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 5310, 6420 };

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="CMFlattenDenseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCMFlattenDenseMatrixType()
        {
            // Arrange
            var multiplicandData = new double[]
                                   {
                                       1, 2,
                                       3, 4,
                                       5, 6
                                   };
            var multiplicand = new CMFlattenDenseMatrix<double>(2, 3, multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 5310, 6420 };

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="CcsSparseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCcsSparseMatrixType()
        {
            // Arrange
            // Matrix:
            // 1 3
            // 0 4
            // 2 0
            var multiplicand = new CcsSparseMatrix<double>(
                rowsCount: 3,
                columnsCount: 2,
                columnsBegins: new[] { 0, 2, 4 },
                rowsIndexes: new[] { 0, 2, 0, 1 },
                data: new double[] { 1, 2, 3, 4 });
            var multiplier = new DenseVector<double>(new double[] { 10, 100 });
            var result = new DenseVector<double>(3);

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(new double[] { 310, 400, 20 }));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="CrcsSparseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCrcsSparseMatrixType()
        {
            // Arrange
            // Matrix:
            // 1 0 2
            // 3 4 0
            var multiplicand = new CrcsSparseMatrix<double>(
                lowTriangleRowsBegins: new[] { 0, 0, 1 },
                lowTriangleColumnsIndexes: new[] { 0 },
                highTriangleColumnsBegins: new[] { 0, 0, 0, 1 },
                highTriangleRowsIndexes: new[] { 0 },
                lowTriangleData: new double[] { 3 },
                diagonalData: new double[] { 1, 4 },
                highTriangleData: new double[] { 2 });
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(2);

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(new double[] { 2010, 430 }));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="CrcsSparseSymmetricMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCrcsSparseSymmetricMatrixType()
        {
            // Arrange
            // Matrix:
            // 1 0 3
            // 0 2 0
            // 3 0 4
            var multiplicand = new CrcsSparseSymmetricMatrix<double>(
                begins: new[] { 0, 0, 0, 1 },
                indexes: new[] { 0 },
                diagonalData: new double[] { 1, 2, 4 },
                triangleData: new double[] { 3 });
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(3);

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(new double[] { 3010, 200, 4030 }));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="CrsSparseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCrsSparseMatrixType()
        {
            // Arrange
            // Matrix:
            // 1 0 2
            // 3 4 0
            var multiplicand = new CrsSparseMatrix<double>(
                rowsCount: 2,
                columnsCount: 3,
                rowsBegins: new[] { 0, 2, 4 },
                columnsIndexes: new[] { 0, 2, 0, 1 },
                data: new double[] { 1, 2, 3, 4 });
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(2);

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(new double[] { 2010, 430 }));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="DenseSymmetricMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasDenseSymmetricMatrixType()
        {
            // Arrange
            // Matrix:
            // 1 2
            // 2 3
            var multiplicandData = new double[] { 1, 2, 3 };
            var multiplicand = new DenseSymmetricMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 210, 320 };

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="RMDenseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasRMDenseMatrixType()
        {
            // Arrange
            var multiplicandData = new[]
                                   {
                                       new double[] { 1, 2, 3 },
                                       new double[] { 4, 5, 6 }
                                   };

            var multiplicand = new RMDenseMatrix<double>(multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 3210, 6540 };

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="RMFlattenDenseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasRMFlattenDenseMatrixType()
        {
            // Arrange
            var multiplicandData = new double[]
                                   {
                                       1, 2, 3,
                                       4, 5, 6
                                   };
            var multiplicand = new RMFlattenDenseMatrix<double>(2, 3, multiplicandData);
            var multiplier = new DenseVector<double>(new double[] { 10, 100, 1000 });
            var result = new DenseVector<double>(2);
            var expectedResult = new double[] { 3210, 6540 };

            // Act
            MatrixExtensions.Multiply(multiplicand, multiplier, result);

            // Assert
            Assert.That(result.Values, Is.EquivalentTo(expectedResult));
        }

        #endregion

        #endregion
    }
}